package com.lzh.runke.core.web_base.helper;

import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.Objects;

/**
 * @Description: 获取 spring bean 实例
 * @Author: LiuZiHao
 * @Date: 2022/5/24 17:48
 */
@Component
public class BeanHelper implements ApplicationContextAware {

    protected static ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }

    /**
     * 获取Bean, 当Bean不存在时抛出NoSuchBeanDefinitionException
     *
     * @param beanClass
     * @param <T>
     * @return
     */
    public static <T> T getBean(Class<T> beanClass) {
        if (Objects.isNull(context)) {
            return null;
        }
        return context.getBean(beanClass);
    }

    /**
     * 获取Bean，当Bean不存在时不抛出异常
     *
     * @param beanClass
     * @param <T>
     * @return
     */
    public static <T> T getBeanSafe(Class<T> beanClass) {
        if (Objects.isNull(context)) {
            return null;
        }
        String[] beanNames = context.getBeanNamesForType(beanClass);
        if (ArrayUtils.isEmpty(beanNames)) {
            return null;
        }
        if (beanNames.length > 1) {
            throw new NoUniqueBeanDefinitionException(beanClass, beanNames);
        }
        return context.getBean(beanNames[0], beanClass);
    }

    /**
     * 获取所有bean实例
     *
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> Map<String, T> getBeansOfType(Class<T> clazz) {
        if (Objects.isNull(context)) {
            return null;
        }
        return context.getBeansOfType(clazz);
    }

    /**
     * 获取Bean, 如果不存在则返回一个Class.newInstance()生成的bean(仅适用于Singleton)
     *
     * @param beanClass
     * @param <T>
     * @return
     */
    public static <T> T getBeanIfAbsent(Class<T> beanClass) {
        T bean = getBeanSafe(beanClass);
        if (Objects.isNull(bean)) {
            return bean;
        }
        return BeanUtils.instantiateClass(beanClass);
    }
}
